;-------------------------------------------------------------------------
;  Copyright (C) 2010-2012 Christopher Brochtrup
;
;  This file is part of Capture2Text.
;
;  Capture2Text is free software: you can redistribute it and/or modify
;  it under the terms of the GNU General Public License as published by
;  the Free Software Foundation, either version 3 of the License, or
;  (at your option) any later version.
;
;  Capture2Text is distributed in the hope that it will be useful,
;  but WITHOUT ANY WARRANTY; without even the implied warranty of
;  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;  GNU General Public License for more details.
;
;  You should have received a copy of the GNU General Public License
;  along with Capture2Text.  If not, see <http://www.gnu.org/licenses/>.
;
;-------------------------------------------------------------------------

#NoEnv                       ; Recommended for performance and compatibility with future AutoHotkey releases.
SendMode Input               ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.
CoordMode, Mouse, Screen     ; Make 0,0 the top-left of screen
SetTitleMatchMode 2          ; Allow partial window title matches
FileEncoding, UTF-8          ; Use UTF-8 file encoding

#Include %A_ScriptDir%/ScreenCapture.ahk
#Include %A_ScriptDir%/Common.ahk

Transaction_Count := 0

IMG_CONV_UTIL       = Utils/ConvertImageFormat/ConvertImageFormat.exe ; The image conversion utility
OCR_UTIL_NHOCR      = Utils/nhocr/nhocr.exe         ; The NHocr OCR tool
OCR_UTIL_TESSERACT  = Utils/tesseract/tesseract.exe ; The Tesseract OCR tool
SUBSTITUTIONS_FILE  = substitutions.txt
; Scale filter algorithm for OCR capture
; 0 = Nearest, 1 = Linear,   2 = Bilinear, 3 = Box,     4 = Triangle,
; 5 = Bell,    6 = B Spline, 7 = Lanczos,  8 = Mitchell
SCALE_FILTER        = 7
ScaleFactor := 3.2

dictionary         = Japanese (NHocr) ; The OCR dictionary to use
subList            := [] ; The substitutions list

; Create ocrDicTable and ocrCodeTable
createLanguageTable()

; Create installedDics
getInstalledDics()

; Set the dictionary directory for the OCR tool
EnvSet, NHOCR_DICDIR, Utils/nhocr/Dic

; Read in the substitutions file
readsubstitutions()

;-------------------------------------------------------------------------

; 既に撮影したbmpファイルにOCRをかける
doOCR(inFile, outFile, ByRef ary_text_out)
{
    global

    ; Capture the screen and OCR it
    ocrText := captureAndOCR_BMP(inFile, outFile)

    ocrText := replaceSpecialChars(ocrText)
    ; 「秘伝の書」等の不要な改行を取り除く
    ary_tmp := {}
    Loop, Parse, ocrText, `n, `r
    {
        ary_tmp.Insert(A_LoopField)
    }

    ; Replace certain characters in the text
    for i, elm in ary_tmp {
        buf := elm
        buf := Trim(buf, "`n")
        buf := Trim(buf, "`r")
        buf := Trim(buf, " ")
        buf := replaceOCRText(buf)
        buf := Trim(buf, "`n")
        buf := Trim(buf, "`r")
        buf := Trim(buf, " ")
        if (StrLen(buf) > 2) {
            ary_text_out.Insert(buf)
        }
    }

    for i, elm in ary_text_out {
        pos1 := RegExMatch(elm, "^\[")
        pos2 := RegExMatch(elm, "\]$")
        if(InStr(elm, "Gold")) {
            continue
        }
        pos3 := RegExMatch(elm, "[0-9,][0-9,][0-9,]")
        if (pos3) {
            continue
        }
        if (pos1 && pos2) {
;            dout("Combined " i " into " i-1 " " elm " ==> " ary_tmp[i-1])
            ary_text_out[i-1] .= " " . elm
            ary_text_out.Remove(i)
        }
    }

    ; Output the OCR'd text based on user-defined settings (default is clipboard)
    ocrText=
    for i, elm in ary_text_out {
        ocrText .= elm . "`r`n"
    }

    ; If the user has specified a file to write the text to
    if(StrLen(outFile) > 0) {
        outFile := outFile . ".txt"
        f := FileOpen(outFile, "w", 65001)
        f.Write(ocrText)
        f.Close()
    }
    return ocrText
}

; Capture the screen and OCR it
; Parameters: integers; The screen coordinates that form the rectangle to capture
; Return Value: The OCR'd text
captureAndOCR_BMP(AryCaptureFile, outFile)
{
    global

    dictionaryCode := ocrDicTable[dictionary]
    ocrUtil := OCR_UTIL_NHOCR

    ; Configure arguments based on OCR util
    ocrOutputFile = %outFile%-tmp.txt

    EnvSet, NHOCR_DICCODES, %dictionaryCode% ; Set the dictionary for the OCR tool

    ocrInputFile = 
    for i, file in AryCaptureFile {
        ocrInputFile .= "Output/screen_capture-" Transaction_Count . "-" i ".ppm "
    }
    ocrUtilArgs = -block -o %ocrOutputFile% %ocrInputFile%

    ; Convert the capture from bitmap to input required by the OCR tool
    for i, file in AryCaptureFile {
        RunWait, %IMG_CONV_UTIL% %file% Output/screen_capture-%Transaction_Count%-%i%.ppm %scaleFactor% %SCALE_FILTER%, , Hide
    }
    ; Run OCR
    RunWait, %ocrUtil%  %ocrUtilArgs%, , Hide

    ; Read the OCR'd text from the OCR tools output
    FileRead, ocrText, %ocrOutputFile%

    for i, file in AryCaptureFile {
        FileDelete, Output/screen_capture-%Transaction_Count%-%i%.ppm
    }
    return ocrText
} ; captureAndOCR


; Replace tokens with special characters
replaceSpecialChars(text)
{
  global

  StringReplace, text, text, ${cr}, , All
  StringReplace, text, text, ${lf}, , All
  StringReplace, text, text, ${tab}, , All

  return text
} ; replaceSpecialChars


; Replace certain characters in the OCR'd text
replaceOCRText(ocrText, force=false)
{
    global

    StringReplace, ocrText, ocrText, `r`n, , All
    StringReplace, ocrText, ocrText, `r, , All
    StringReplace, ocrText, ocrText, `n, , All

    ; Trim whitesapce from start and end
    ocrText := Trim(ocrText, "`n")
    ocrText := Trim(ocrText, "`r")
    ocrText := Trim(ocrText, " ")

    Loop,2
        ocrText := performsubstitutions(ocrText)

    return ocrText

} ; replaceOCRText()


; Read in the substitutions file. Parses the "All:" and current OCR language sections
readsubstitutions()
{
  global
  Local line_count, last_dic

  ; Clear substitutions list
  subList := []

  ; File parse state
  ; 0 = Searching for All: section
  ; 1 = Looping through All: section
  ; 2 = Searching for current OCR language section
  ; 3 = Looping through current OCR language section
  ; 4 = Done
  state = 0
  line_count = 0
  last_dic =
  ; Read the substitutions file
  Loop, read, %SUBSTITUTIONS_FILE%
  {
    line_count++
    if(state == 0)
    {
      if(A_LoopReadLine == "All:")
      {
        state = 1
      }
    }
    else if((state == 1) || (state == 3))
    {
      StringLeft, firstChar, A_LoopReadLine, 1

      ; If the line is blank or is a comment
      if((StrLen(A_LoopReadLine) == 0) || (firstChar == "#"))
      {
        continue
      }

      ; If the line contains "="
      if(InStr(A_LoopReadLine, "="))
      {
        subList.Insert(A_LoopReadLine)
        last_dic := A_LoopReadLine
      }
      else
      {
        OutputDebug % "Read " line_count " lines for dictionary: " dictLine ". Last dict:" last_dic
        if(state == 1)
        {
          state = 2
        }
        else
        {
          state = 4
        }
      }
    }
    else if(state == 2)
    {
      dictLine = %dictionary%:

      if(A_LoopReadLine == dictLine)
      {
        state = 3
      }
    }
    else if(state == 4)
    {
      break
    }
  }

} ; readsubstitutions

convert_alpha(text) {
    text := RegExReplace(text, "a", "3")
    text := RegExReplace(text, "o", "0")
    text := RegExReplace(text, "[ijl｜]", "1")
    text := RegExReplace(text, "[s]", "5")
    return text
}

; ノアピースや秘伝の書の不正な改行を組み替える。
; ※ 妥協: 「秘伝の書」とか前についてるのは諦める
/* 例
[@1,800,000 Gold] マジカル ブラシ セッ ト
[@1,000,000 Gold] 秘伝の書[ ワイド スターマイン ]
[@400,000 Gold] 秘伝の書 [ モラール ブースター ]
[@250,000 Gold] 秘伝の書 [ ブーステッ ド レッグス ]
[@200,000 Gold] ノアピース[ クイックサンド ]
[@200,000 Gold] 秘伝の書 [ ミスト フォーム ]
[@200,000 Gold] ノアピース[ グループ ブラッ ド ラッシュ ]
[@150,000 Gold] 秘伝の書 [ インバクト ウェーブ ]
[@150,000 Gold] ノアピース[e｜50,000 Gold] ノアピース[@j50,000 Gold] ノアピース[@100,000 Gold] ノアピース[ ファイアー ストーム]
[ ウォーター アート ]
[ グルーブ クイックニング]
[スタヴキイション ]
[@100,000 Gold] 秘伝の書 [ ダークネス フォース ]
[@50,000 Gold] 秘伝の書 [ 鬼火]
[@40,000 Gold] ノアピース [ リザレクション オール ]
[@20,000 Gold] 秘伝の書 [ ウォーター ストリーム ]
*/
correct_noa_piece(text) {
    aryPrefix := []
    buf := text
    deleted_str =
    Loop, 20
    {
        ; 改行の重なりを削る ← 削りすぎた・・
        ;buf := RegExReplace(buf, "`r`n`r`n", "")

        pos1 := RegExMatch(buf,         "\[[0-9,@]+ Gold\] 秘伝の書", prefix1)
        pos2 := RegExMatch(buf,         "\[[0-9,@]+ Gold\] ノアピース", prefix2)
        pos3 := RegExMatch(buf,         "\[[0-9,@]+ Gold\] 究極奥儀の書", prefix3)
        pos4 := RegExMatch(buf,         "\[[0-9,@]+ Gold\] からくりキット", prefix4)
        if (!pos1 && !pos2 && !pos3 && !pos4) {
            break   ; 何も見つからず。
        }

        ; 一番最初に見つかる価格情報を得る
        pos1 := pos1 ? pos1 : 999
        pos2 := pos2 ? pos2 : 999
        pos3 := pos3 ? pos3 : 999
        pos4 := pos4 ? pos4 : 999
        least_len := 99999
        least_item := 0
        Loop, 4
        {
            if (least_len > pos%A_Index%) {
                least_item := A_Index
                least_len := pos%A_Index%
            }
        }
        ;outputdebug % pos1 "," pos2 "," pos3 "," pos4 "," "L_Len: " least_len "(" least_item ")"
        if (least_item == 1) {
            buf := RegExReplace(buf,    "\[[0-9,@]+ Gold\] 秘伝の書", "", 0, 1, pos1)

            ; 次に見つかる名称を連結する
            pos := RegExMatch(buf,      "\[[ a-zA-Z\.\\0-9ぁ-ーァ-ヶァ-ヴ一-龠ー∞｜]+\]", suffix, pos1)
            ;outputdebug % "Append: " prefix1 suffix
            aryPrefix.Insert(prefix1 suffix "`r`n")
            buf := RegExReplace(buf,    "\[[ a-zA-Z\.\\0-9ぁ-ーァ-ヶァ-ヴ一-龠ー∞｜]+\]", "", 0, 1, pos)
            continue
        }

        if (least_item == 2) {
            buf := RegExReplace(buf,        "\[[0-9,@]+ Gold\] ノアピース", "", 0, 1, pos2)
            ; 次に見つかる名称を連結する
            pos := RegExMatch(buf,      "\[[ a-zA-Z\.\\0-9ぁ-ーァ-ヶァ-ヴ一-龠ー∞｜]+\]", suffix, pos2)
            ;outputdebug % "Append: " prefix2 suffix
            aryPrefix.Insert(prefix2 suffix "`r`n")
            buf := RegExReplace(buf,    "\[[ a-zA-Z\.\\0-9ぁ-ーァ-ヶァ-ヴ一-龠ー∞｜]+\]", "", 0, 1, pos)
            continue
        }
        if (least_item == 3) {
            buf := RegExReplace(buf,        "\[[0-9,@]+ Gold\] 究極奥儀の書", "", 0, 1, pos3)
            ; 次に見つかる名称を連結する
            pos := RegExMatch(buf,      "\[[ a-zA-Z\.\\0-9ぁ-ーァ-ヶァ-ヴ一-龠ー∞｜]+\]", suffix, pos3)
            ;outputdebug % "Append: " prefix3 suffix
            aryPrefix.Insert(prefix3 suffix "`r`n")
            buf := RegExReplace(buf,    "\[[ a-zA-Z\.\\0-9ぁ-ーァ-ヶァ-ヴ一-龠ー∞｜]+\]", "", 0, 1, pos)
            continue
        }
        if (least_item == 4) {
            buf := RegExReplace(buf,        "\[[0-9,@]+ Gold\] からくりキット", "", 0, 1, pos4)
            ; 次に見つかる名称を連結する
            pos := RegExMatch(buf,      "\[[ a-zA-Z\.\\0-9ぁ-ーァ-ヶァ-ヴ一-龠ー∞｜]+\]", suffix, pos4)
            ;outputdebug % "Append: " prefix4 suffix
            aryPrefix.Insert(prefix4 suffix "`r`n")
            buf := RegExReplace(buf,    "\[[ a-zA-Z\.\\0-9ぁ-ーァ-ヶァ-ヴ一-龠ー∞｜]+\]", "", 0, 1, pos)
            continue
        }
    }
    for i, elm in aryPrefix {
        deleted_str .= elm
    }

    buf .= "`r`n" deleted_str
    buf := RegExReplace(buf, "(`r`n)+", "`n")
    buf := RegExReplace(buf, "`n", "`r`n")
   ;msgbox % buf
    return buf
}

; 花びらの番号以降を削る(細かい数字の判別は無理！)
remove_hanabira(text) {
; ター ・ フルークの花びら 07 (84S 228 80%)
; ター ・ フルークの花びら 11 (88 808
; ター ・ メリアの花びら 04 (l8S 488 12持)
; ター ・ メリアの花びら 08 (48S ｜88

    text := RegExReplace(text, "花ひら", "花びら")
    ;text := RegExReplace(text, "花びら ([0-9])([0-9])[ ]*[a-zA-Z0-9%ぁ-ーァ-ヶァ-ヴ一-龠ー∞｜\(\) ]+$",  "花びら ${1}${2}")
    pos := InStr(text, "花びら ")
    if(pos) {
        text := SubStr(text, 1, pos+5)
    }
    return text
}

; Perform substitutions on the provided text.
; Global inputs:
;   subList
performsubstitutions(text)
{
  global

    text := RegExReplace(text, "∞$",  "0)")
    text := RegExReplace(text, "^胞",  "[@")
    text := RegExReplace(text, "^碑",  "[@")
    text := RegExReplace(text, "^Fr",  "[1")
    text := RegExReplace(text, "^\[e", "[@")

    text := RegExReplace(text, "^胞", "[@")
    text := RegExReplace(text, "^碑", "[@")

    text := RegExReplace(text, "\[@｜", "[@1")
    text := RegExReplace(text, "\[｜", "[1")

    text := RegExReplace(text, "([ァ-ヶー]+)L([ァ-ヶー]+)", "${1}ー${2}")

    text := RegExReplace(text, "([ァ-ヶー]+)7", "${1}ア")
    text := RegExReplace(text, "7([ァ-ヶー]+)", "ア${1}")

    text := RegExReplace(text, "([ァ-ヶー]+)茸", "${1}ダ")
    text := RegExReplace(text, "茸([ァ-ヶー]+)", "ダ${1}")

    ; 髪型や顔の見本の修正
    text := RegExReplace(text, "(本 N)[a-z][a-z]([1-9])", "${1}o.${2}")

    ; たっぷり すも7< ふ7<ら
    text := RegExReplace(text, "([ぁ-ー]+)7", "${1}っ")
    text := RegExReplace(text, "7([ぁ-ー]+)", "っ${1}")
    ; なり舌り → なりきり
    text := RegExReplace(text, "([ぁ-ー]+舌[ぁ-ー]+)", "${1}き${2}")

    ; ゴしルデン = ゴールデン
    text := RegExReplace(text, "([ァ-ヶ]+)し([ァ-ヶ]+)", "${1}ー${2}")

    ; 「力【ちから】」→カタカナのカ への補整
    text := RegExReplace(text, "([ァ-ヶー]+)力", "${1}カ")
    text := RegExReplace(text, "力([ァ-ヶー]+)", "カ${1}")

    ; 「バトル」への補整
    text := RegExReplace(text, "ノ[a-z\\'A-Z]*[ト卜]*[a-z\\'A-Z]*[ルレ]", "バトル")
    ; 前後にスペースの空いてしまった「ト」への補整
    text := RegExReplace(text, "([ァ-ヶー])[ ]+[ト卜][ ]+([ァ-ヶー])", "${1}ト${2}")

    ; カタカナの中のfl -> ト
    text := RegExReplace(text, "([ァ-ヶー])fl", "${1}ト")
    text := RegExReplace(text, "fl([ァ-ヶー])", "ト${1}")

    ; 耐久度の中の文字化けを数値に変更(左側)
    text := RegExReplace(text, "\(vo([0-9]*)/",      "(100${1}/")
    text := RegExReplace(text, "\(ij([0-9]*)/",      "(17${1}/")
    text := RegExReplace(text, "\(s([0-9]*)/",       "(3${1}/")
    text := RegExReplace(text, "\(([0-9]*)o/",       "(${1}0/")
    text := RegExReplace(text, "\(o([0-9]*)/",       "(0${1}/")
    text := RegExReplace(text, "\([ijl]([0-9]*)/",   "(1${1}/")
    text := RegExReplace(text, "\(([0-9]*)[ij]/",    "(${1}1/")
    text := RegExReplace(text, "\(([0-9]*)[ijl｜]/", "(${1}1/")
    text := RegExReplace(text, "\([ijl｜]([0-9]*)/", "(1${1}/")
    text := RegExReplace(text, "\([帥恥]o/",         "(600/")

    ; 耐久度の中の文字化けを数値に変更(右側)
    text := RegExReplace(text, "/([0-9]*)o\)",       "(/${1}0)")
    text := RegExReplace(text, "/s([0-9]*)\)",       "(/3${1})")
    text := RegExReplace(text, "/([0-9]*)s\)",       "(/${1}3)")
    text := RegExReplace(text, "/[帥恥]o\)",          "/600)")

    ; (v3/
    ;text := RegExReplace(text, "\(v([0-9]+)/)", "(1${1}/") ; 何故か全部消える
    ; (1500( カッコの重なり
    text := RegExReplace(text, "\(([0-9a-zA-Z]+)\(", "(${1}")

    ; 「ト」「ド」の前のスペースを削る(トで始まる単語で例外もある ミスリル トール など)
    len1 = StrLen(text)
    text := RegExReplace(text, "([ァ-ヶァ-ヴーッ]+)[ ]+([トド][ァ-ヶァ-ヴーッ ]+)", "${1}${2}")
    len2 = StrLen(text)
    text := RegExReplace(text, "([ァ-ヶァ-ヴーッ]+) ([トド][ァ-ヶァ-ヴーッ ]+)", "${1}${2}")

    text := RegExReplace(text, "(ミスリル|スチール|アイアン|シルバー|ゴールド|ブロンズ)トール", "${1} トール")
    text := RegExReplace(text, "([ァ-ヶァ-ヴーッ]+)ドラキア", "${1} ドラキア")
    text := RegExReplace(text, "([ァ-ヶァ-ヴーッ]+)ドミグラス", "${1} ドミグラス")
    text := RegExReplace(text, "([ァ-ヶァ-ヴーッ]+)トルネード", "${1} トルネード")
    text := RegExReplace(text, "([ァ-ヶァ-ヴーッ]+)トンファー", "${1} トンファー")
    text := RegExReplace(text, "([ァ-ヶァ-ヴーッ]+)トランペット", "${1} トランペット")
    text := RegExReplace(text, "([ァ-ヶァ-ヴーッ]+)トゥシューズ", "${1} トゥシューズ")
    text := RegExReplace(text, "([ァ-ヶァ-ヴーッ]+)ドゥーリン", "${1} ドゥーリン")

    ; "fl"から始まる耐久度の補整     " fl2/12)"
    text := RegExReplace(text, " f[lf]([0-9/\)a-zA-Z]+)", " (1${1}")

    ; " flVr10)" => (1Vr10)

    ; [10/10)
    text := RegExReplace(text, "\[([0-9]+/[0-9]+\))", "(${1}")

    ; ー22/22)
    text := RegExReplace(text, "ー([0-9]+/[0-9]+\))", " (${1}")

    ; (バンダゝ
    text := RegExReplace(text, "\(([ァ-ヶァ-ヴーッ]+)ゝ", " (${1})")

    ; ハ5)
    text := RegExReplace(text, "ハ([0-9]+\))", "/1${1}")

    ; 価格の訂正 [e｜50,000 Gold] [@j50,000 Gold]
    text := RegExReplace(text,  "\[e([ij｜0-9,]+) Gold]", "[@${1} Gold]")
    text := RegExReplace(text,  "\[@[ij｜]([0-9,]+) Gold]", "[@1${1} Gold]")

  ; Loop through substitutions list
  Loop % subList.MaxIndex()
  {
    ; Get current substitution
    curSub := % subList[A_Index]

    ; Extract the from and to portions of the substitution
    StringSplit, fields, curSub, =
    replaceFrom = %fields1%
    replaceTo = %fields2%

    ; Replace special tokens
    StringCaseSense, On
    StringReplace, replaceFrom, replaceFrom, `%cr`%, `r, All
    StringReplace, replaceTo, replaceTo, `%cr`%, `r, All

    StringReplace, replaceFrom, replaceFrom, `%eq`%, =, All
    StringReplace, replaceTo, replaceTo, `%eq`%, =, All

    StringReplace, replaceFrom, replaceFrom, `%lf`%, `n, All
    StringReplace, replaceTo, replaceTo, `%lf`%, `n, All

    StringReplace, replaceFrom, replaceFrom, `%perc`%, `%, All
    StringReplace, replaceTo, replaceTo, `%perc`%, `%, All

    StringReplace, replaceFrom, replaceFrom, `%space`%, %A_Space%, All
    StringReplace, replaceTo, replaceTo, `%space`%, %A_Space%, All

    StringReplace, replaceFrom, replaceFrom, `%tab`%, %A_Tab%, All
    StringReplace, replaceTo, replaceTo, `%tab`%, %A_Tab%, All

    ; Perform substitution
    StringReplace, text, text, %replaceFrom%, %replaceTo%, All
    StringCaseSense, Off
  }

    text := RegExReplace(text, "^Fr", "[1")
    text := RegExReplace(text, "^\[e", "[@")

    ; 価格に含まれる数字以外の文字を、適当な数字に補正する。
    text := RegExReplace(text, "([0-9]+)Gold\]",   "${1} Gold]")    ; スペースがなかったら、空ける

    ; 価格の部分だけ、一旦切り出す。
    endpos := InStr(text, "Gold")
    if (endpos) {
       ; msgbox % endpos
        buf1 := SubStr(text, endpos)
        StringLeft, buf2, text, endpos-1
        buf2 := RegExReplace(buf2, "[vo]", "0")
        buf2 := RegExReplace(buf2, "[ijl｜]", "1")
        buf2 := RegExReplace(buf2, "[ー]", "")
        buf2 := RegExReplace(buf2, "[z]", "2")
        buf2 := RegExReplace(buf2, "[呼]", "[@2")
        buf2 := RegExReplace(buf2, "[ヰ]", "4")
        buf2 := RegExReplace(buf2, "[ty]", "4")
        buf2 := RegExReplace(buf2, "[s]", "5")
        buf2 := RegExReplace(buf2, "[i)B]", "6")
        buf2 := RegExReplace(buf2, "[ァ郎wW了]", "@7")
        buf2 := RegExReplace(buf2, "[Ff]", "[")
        buf2 := RegExReplace(buf2, "\[g", "[@")
        buf2 := RegExReplace(buf2, "[ag]", "9")
        buf2 := RegExReplace(buf2, "[¢sR]", "[2")
        buf2 := RegExReplace(buf2, "[%]", "[6")
        buf2 := RegExReplace(buf2, "[p]", "[7")
        ; 元の文字を連結
        text := buf2 . buf1
    }

    ; ペットや時の石のレベル値で、変換に失敗したものを削る
    ; 例: <破壊魔法:lvoij>
    pos := RegExMatch(text,        ":[a-zA-Z\.\\0-9ぁ-ーァ-ヶァ-ヴ一-龠ー∞｜]+[>]*$", m_res)
    if (pos) {
      ; outputdebug % "m_res: " m_res
        text := RegExReplace(text, ":[a-zA-Z\.\\0-9ぁ-ーァ-ヶァ-ヴ一-龠ー∞｜]+[>]*$", "")
        m_res := convert_alpha(m_res)
        m_res := RegExReplace(m_res, "[^0-9\.]", "")
        text .= ":" m_res
        if(!RegExMatch(m_res, ">$")) {
            text .= ">"
        }
    }
;    outputdebug % "[" A_LineNumber "]" text

    ; 他に影響する(よく含まれる)ため、完全一致じゃないと置換しない。
    text := RegExReplace(text, "[ ]+.\\.$", " 砂糖")
    text := RegExReplace(text, "[ ]+アンブ$", " アンプ")
    text := RegExReplace(text, "[ ]+バスタ$", " パスタ")
    text := RegExReplace(text, "[ ]+98$", " 餡")
    text := RegExReplace(text, "[ ]+\.$", " 指")
    text := RegExReplace(text, "[ ]+\.\$", " 酢")
    text := RegExReplace(text, "[ ]+ビサ$", " ピザ")

    text := RegExReplace(text, "へ([ア-ン])", "ヘ${1}")
/*
    if (InStr(text, "へ")) {
        if (!RegExMatch(text, "へ[あ-ん]")) {
            text := RegExReplace(text, "へ", "ヘ")
        }
    }
*/

    ; <スロット+2)
    text := RegExReplace( text, "(<スロット\+[0-9a-zA-Z]+)\)", "${1}>")

    if(InStr(text, "地図")) {
        Loop, 3
        {
            ; カッコの不一致の修正
            text := RegExReplace( text, "地図 <([0-9]+)\)", "地図 <${1}>")
            text := RegExReplace( text, "地図 \(([0-9]+)>", "地図 <${1}>")

            ; 地図 <2i8>
            text := RegExReplace( text, "地図 <([0-9]*)[ijl｜]([0-9]*)>", "地図 <${1}1${2}>")
            text := RegExReplace( text, "地図 <([0-9b-zA-Z]*)[a]([0-9b-zA-Z]*)>", "地図 <${1}3${2}>")
            ; 地図 <i28>
            text := RegExReplace( text, "地図 <[ijl｜]([0-9]*)>", "地図 <1${1}>")
            ; <2ja>
        }
    }

    StringReplace, text, text, gosick, GOSICK
    StringReplace, text, text, wgk, WGK
    StringReplace, text, text, sgk, SGK
    StringReplace, text, text, egk, EGK
    StringReplace, text, text, ngk, NGK
    StringReplace, text, text, cf, CF

    ; カッコが閉じていない耐久度の修正
    text := RegExReplace( text, "(\([0-9a-zA-Z]+/[0-9a-zA-Z]+)$", "${1})")
    text := RegExReplace( text, "(\([0-9]+/[0-9]+)$", "${1})")

    ; (15ハ5) = (15/15)
    text := RegExReplace( text, "(\([0-9]+)ハ([0-9\)]+)$", "${1}/1")

    ; ホムンクルス人形 <NF)
    text := RegExReplace( text, "ホムンクルス人形 [<\(]([a-zA-Z]+)[\)>]", "ホムンクルス人形(${1})")
    ; (l5ty托o)
    text := RegExReplace( text, "\(([0-9a-zA-Z]+)[托ハ]+([0-9a-zA-Z]+)\)", "(${1}/1${2})" )

    ; {スロット+4>
    ;text := RegExReplace( text, "{", "(")
    text := RegExReplace( text, "[{<\(]スロット\+([0-9]+)[\)>}]", "(スロット+${1})")

    ; (jtyvo) = (j0/vo)
    text := RegExReplace( text, "([0-9a-zA-Z]+)ty([0-9a-zA-Z]+)\)", "${1}0/${2})")

    ; 耐久度の中の文字以外を適当に修正
    pos := RegExMatch(text,        "/[0-9a-zA-Zぁ-ーァ-ヶァ-ヴ一-龠ー∞｜]+\)$", m_res)
    if (pos) {
        text := RegExReplace(text, "/[0-9a-zA-Zぁ-ーァ-ヶァ-ヴー一-龠∞｜]+\)$", "")
        m_res := convert_alpha(m_res)
        m_res := RegExReplace(m_res, "[/\)]", "")
        m_res := RegExReplace(m_res, "[^0-9]", "0")
        text .= "/" m_res ")"
    }

    ; (lVi7)
    ; (iVi7)
    ; (lVi7)
    text := RegExReplace( text, "\([0-9a-zA-Z]+V[0-9a-zA-Z]+\)", "(17/17)")
    text := RegExReplace( text, "\([0-9a-zA-Z]+ハ[0-9a-zA-Z]+\)", "(17/17)")

    text := RegExReplace( text, "[\(<]([赤青白黄緑黒橙])[\)>]", "(${1})")

    ; (｜500/｜50∞ = (1500/1500)
    text := RegExReplace( text, "(/[0-9]+)∞", "${1}0)")

;    ; 括弧の中の数字を並べ替える(未完成)
;    buffi =
;    Loop, Parse, text, `n, `r
;    {
;        if(StrLen(A_LoopField) < 3) {
;            continue
;        }
;        pos := RegExMatch(A_LoopField, "\([0-9a-zA-Zぁ-ーァ-ヶァ-ヴ一-龠ー∞｜]+/", m_res)
;        if (pos) {
;            buffi2 := RegExReplace(A_LoopField, "\([0-9a-zA-Z｜ぁ-ーァ-ヶァ-ヴー一-龠∞]+/", "")
;            m_res := convert_alpha(m_res)
;            m_res := RegExReplace(m_res, "[\(/]", "")
;            m_res := RegExReplace(m_res, "[^0-9]", "0")
;            pos2 := RegExMatch(buffi2, "[0-9]+\)$", lower_str)
;            if (pos2) {
;                buffi2 := RegExReplace(buffi2, "[0-9]+\)$", "")
;            }
;            buffi2 .= "(" m_res "/"
;            if (pos2) {
;                buffi2 .= lower_str
;            }
;            buffi .= buffi2 . "`r`n"
;            continue
;        }
;        buffi .= A_LoopField "`r`n"
;    }
;    text := buffi

    ; (jo叫voo)
    text := RegExReplace(text,  "\(([0-9a-zA-Z]+)叫([0-9a-zA-Z]+)\)$", "(${1}/${2})")

    ; 削られた耐久度の補完 「びっくりハンマー 9)」
    text := RegExReplace(text,  " ([0-9]+)\)$", " (${1}/${1})")
    text := RegExReplace(text,  " ([0-9]+)\)`r`n", " (${1}/${1})`r`n")

    ;  Viハア)
;    text := RegExReplace( text, " [\(]*[0-9a-zA-Z｜ぁ-ーァ-ヶァ-ヴー一-龠∞]+ハ", " (17/1")
;    text := RegExReplace( text, "(/[0-9]+)ア\)[ ]*", "${1}7)")
;    outputdebug % "[" A_LineNumber "]" text

    text := RegExReplace(text,  "から<り", "からくり")
    text := RegExReplace(text,  "キッ ト", "キット")
;   text := correct_noa_piece(text)

    ; f19/19) = (19/19)
    text := RegExReplace(text,  " f[0-9]+/[0-9a-zA-Z]+\)", " (19/19)")
    text := RegExReplace(text,  " \([^0-9]+/([0-9]+)\)",   " (${1}/${1})")
    text := RegExReplace(text,  " \(([0-9]+)/[^0-9]+\)",   " (${1}/${1})")
    text := RegExReplace(text,  " \([^0-9]+/[^0-9]+\)",    " (11/11)")

    ; (1t/17)
    text := RegExReplace(text,  "/([0-9])[^0-9]+\)",    "/${1}${1})")
    text := RegExReplace(text,  "/[^0-9]+([0-9])\)",    "/${1}${1})")
    text := RegExReplace(text,  " \(([0-9])[^0-9]+/",   " (${1}${1}/")
    text := RegExReplace(text,  " \([^0-9]([0-9])/([0-9]+)\)",   " (${1}${1}/${2})")

    text := remove_hanabira(text)

    ; ペットや時の石のレベル値で、変換に失敗したものを削る
    ; 例: <破壊魔法:lvoij>
    tpos := RegExMatch(text, ":[a-zA-Z\.\\0-9]+>$", m_res)
    if (tpos) {
       ; outputdebug % "m_res: " m_res
        buffi2 := RegExReplace(text, ":[a-zA-Z\.\\0-9]+>$", "")
        m_res := RegExReplace(m_res, "a0", "30")
        m_res := RegExReplace(m_res, "a", "9")
        m_res := RegExReplace(m_res, "B", "6")
;       m_res := RegExReplace(m_res, "jf", "0.")
        m_res := RegExReplace(m_res, "[vo]", "00")
        m_res := RegExReplace(m_res, "[ijl｜]", ":10.1")
        m_res := RegExReplace(m_res, "[^0-9\.]", "")
        text := buffi2 . m_res
    }

    ; 地図の番号変換に失敗したものを補正する
    tpos := RegExMatch(text, "<[a-zA-Z｜0-9]+>$", m_res)
    if (tpos) {
        ;OutputDebug % "m_res: " m_res
        buffi2 := RegExReplace(text, "<[a-zA-Z｜0-9]+>$", "")
        m_res := RegExReplace(m_res, "a0", "30")
        m_res := RegExReplace(m_res, "a", "9")
        m_res := RegExReplace(m_res, "B", "6")
        m_res := RegExReplace(m_res, "[vo]", "0")
        m_res := RegExReplace(m_res, "s3", "39")
        m_res := RegExReplace(m_res, "[ijl｜]", ":10.1")
       ;m_res := RegExReplace(m_res, "[^0-9\.]", "")
        text := buffi2 . m_res
    }
    text := append_paren(text)
    text := insert_colon(text)

    if (InStr(text, "アニマルソウル")) {
        text := RegExReplace(text, "<", "(")
        text := RegExReplace(text, ">", ")")
    }

  return text

} ; performsubstitutions

is_need_colon(text) {
    if (!InStr(text, "<")) {
        return 0
    }
    if (InStr(text, "時の石")) {
        return 1
    }
    if (InStr(text, "アニマル ケイジ")) {
        return 1
    }
    return 0
}

insert_colon(text) {
    if (!is_need_colon(text)) {
        return text
    }

    ;アニマル ケイジ<ミニ イビルタイタン1.0>    before
    ;アニマル ケイジ<ミニ イビルタイタン:1.0>   after
    text := RegExReplace(text, "<([a-zA-Zぁ-ーァ-ヶァ-ヴー一-龠∞ ]+)([0-9.]+)>", "<${1}:${2}>")
    return text
}

match_paren(text) {
    if (!InStr(text, "<")) {
        return 0
    }
    if (InStr(text, "時の石")) {
        return 1
    }
    if (InStr(text, "の石")) {
        return 1
    }
    if (InStr(text, "古びた地図")) {
        return 1
    }
    if (InStr(text, "悟りの石")) {
        return 1
    }
    if (InStr(text, "賢者の石")) {
        return 1
    }
    if (InStr(text, "テレポート ストーン")) {
        return 1
    }
    if (InStr(text, "アニマル ケイジ")) {
        return 1
    }
    return 0
}

append_paren(text) {
    if (!match_paren(text)) {
        return text
    }
    text := Trim(text)
    if(RegExMatch(text, ">")) {
        return text
    }
    ;OutputDebug, % text
    text := RegExReplace(text, ">", "")
    text .= ">"
    return text
}
